package ControllerApplication;

import jAudioFeatureExtractor.jAudioTools.FFT;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

import ModelApplication.Sound;
import ProcessingAudioWindows.AudioProcessingWindowLocal;
import ProcessingAudioWindows.F2AudioProcessingWindow;
import UtilsApplication.ChartTypes;
import UtilsApplication.Complex;
import UtilsApplication.DetectNotes;
import UtilsApplication.FourierUtil;
import UtilsApplication.HandleAudioUtil;

public class F2AudioProcessing extends AudioProcessing {

    public F2AudioProcessing( String methodName, AudioProcessingWindowLocal imgWindow ) {
        super( methodName, imgWindow );
    }
    @Override
    public List<Sound> processingList(Sound sound) {

        F2AudioProcessingWindow imgW = (F2AudioProcessingWindow) imgWindow;
        List<Sound> sounds = new ArrayList<Sound>();
        double [] origAudio = sound.getAudio();

        // wykrywanie tonow w sekwencji
        if (imgW.isDetectNotes()) {
           sounds.addAll( DetectNotes.detectNotes( sound, this, 0));
        } else {
            double [] audio = Arrays.copyOfRange( origAudio, origAudio.length/2, origAudio.length/2 + (int)sound.getWavFile().getSampleRate()/20 );
            double freq = findFundamentalFreq( sounds, audio, sound, imgW.isShowSteps(), true );

            double [] newAudio = HandleAudioUtil.createTone(freq, origAudio.length, (int)sound.getWavFile().getSampleRate() );
            sounds.add( new Sound(newAudio, sound.getWavFile(), null, "cepstrum", sound.getName(), "wygenerowanyDzwiek") );
        }

        return sounds;
    }

    public double findFundamentalFreq(List<Sound> sounds, double [] audio, Sound sound, int zcrMethod) {
        return findFundamentalFreq(sounds,audio, sound, false, false);
    }

    private double findFundamentalFreq(List<Sound> sounds, double [] audio, Sound sound, boolean showSteps, boolean isCreateSound) {

        if(showSteps) {
            sounds.add( new Sound(Arrays.copyOf( audio, audio.length ), sound.getWavFile(), null, "cepstrum", sound.getName(), "probka", ChartTypes.VALUE_AMPLITUDE ) );
        }

        if(showSteps) {
            sounds.add( new Sound(audio, sound.getWavFile(), null, "cepstrum", sound.getName(), "okienkowanieHanninga", ChartTypes.VALUE_AMPLITUDE ) );
        }
        
        // transformata
        FFT fft = null;
        try {
            fft = new FFT(audio, null, false, true );
        } catch ( Exception e1 ) {
            e1.printStackTrace();
        }
        
        //double [] spectrum = fft.getMagnitudeSpectrum();
        double [] realValues = fft.getRealValues();
        double [] phaseValues = fft.getImaginaryValues();
        double [] spectrum = new double[audio.length];
        
        // obciecie do polowy
        for(int i = 0; i < spectrum.length ; i++) {
            spectrum[i] =  Math.sqrt( realValues[i] * realValues[i] + phaseValues[i]*phaseValues[i] ); ;
        }    
           
        if(showSteps) {
            sounds.add( new Sound(Arrays.copyOf( spectrum, spectrum.length ), sound.getWavFile(), null, "cepstrum", sound.getName(), "transformacja1", ChartTypes.FREQ_VALUE) );
        }

        // logarytm
        for (int i = 0; i < spectrum.length; i++) {
            spectrum[i] = Math.log(spectrum[i]);
        }
       
        try {
            fft = new FFT(spectrum, null, false, false );
        } catch ( Exception e ) {
            e.printStackTrace();
        }
        double [] cepstrum = fft.getMagnitudeSpectrum();

        double freq = (double)sound.getWavFile().getSampleRate();
        int per = 10;
        int perLocal = 0;
        int indexMin = 0;
        for(int i = 0; i < cepstrum.length - 1; i++) {
            if(cepstrum[i] < cepstrum[i + 1]){
                if(perLocal++ > per ) {
                    indexMin = i;
                    break;
                }
            }
        }

        // szuanie max
        double maxPeak = -1;
        int indexMax = -1;
        for(int i = indexMin; i < cepstrum.length; i++) {
            if(cepstrum[i] > maxPeak) {
                maxPeak = cepstrum[i];
                indexMax = i;
            }
        }

        double fundamentalFreq =  freq / indexMax;
        if(isCreateSound) {
            Sound cepSound = new Sound(cepstrum, sound.getWavFile(), null, "cepstrum", sound.getName(), "transformacja2", ChartTypes.VALUE_VALUE);
            cepSound.setBaseFreq(fundamentalFreq);
            sounds.add( cepSound );
        }

        return fundamentalFreq;
    }
}
